package com.lhh.apst.library;

import com.lhh.apst.library.utils.TypedAttrUtils;
import ohos.agp.colors.RgbColor;
import ohos.agp.components.*;
import ohos.agp.components.element.Element;
import ohos.agp.components.element.PixelMapElement;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.text.Font;
import ohos.agp.utils.Color;
import ohos.agp.utils.Rect;
import ohos.agp.utils.TextAlignment;
import ohos.app.Context;
import ohos.global.resource.NotExistException;
import ohos.global.resource.ResourceManager;
import ohos.global.resource.WrongTypeException;
import ohos.media.image.PixelMap;
import ohos.utils.PlainArray;

import java.io.IOException;
import java.util.Locale;

/**
 * Created by linhomhom on 2015/8/10.
 */
public class AdvancedPagerSlidingTabStrip extends ScrollView implements Component.DrawTask,
        Component.EstimateSizeListener {
    /**
     * 布局属性接口
     *
     * @since 2021-04-30
     */
    public interface LayoutProvider {
        /**
         * 比重
         *
         * @param position tab位置
         * @return 比重值
         */
        float getPageWeight(int position);

        /**
         * 布局规则
         *
         * @param position tab位置
         * @return 规则数组
         */
        int[] getPageRule(int position);

        /**
         * 获取margin属性
         *
         * @param position tab位置
         * @return Margins
         */
        Margins getPageMargins(int position);
    }

    /**
     * Tips属性接口
     *
     * @since 2021-04-30
     */
    public interface TipsProvider {
        /**
         * Tips Rule
         *
         * @param position tab位置
         * @return 布局集合
         */
        int[] getTipsRule(int position);

        /**
         * TipsMargins
         *
         * @param position tab位置
         * @return Margins
         */
        Margins getTipsMargins(int position);

        /**
         * TipsDrawable
         *
         * @param position tab位置
         * @return Element
         */
        Element getTipsDrawable(int position);
    }

    /**
     * IconTab接口
     *
     * @since 2021-04-30
     */
    public interface IconTabProvider {
        /**
         * 获取PageIcon
         *
         * @param position tab位置
         * @param <T>      Icon泛型
         * @return Icon
         */
        <T extends Object> T getPageIcon(int position);

        /**
         * 获取选中icon
         *
         * @param position tab位置
         * @param <T>      Icon泛型
         * @return Icon
         */
        <T extends Object> T getPageSelectIcon(int position);

        /**
         * 获取icon Bounds
         *
         * @param position tab位置
         * @return Icon
         */
        Rect getPageIconBounds(int position);
    }

    /**
     * ViewTabProvider
     *
     * @since 2021-04-30
     */
    public interface ViewTabProvider {
        /**
         * 选中的IconView
         *
         * @param position tab位置
         * @param view     Component
         * @param parent   ComponentContainer
         * @return Component
         */
        Component onSelectIconView(int position, Component view, ComponentContainer parent);

        /**
         * IconView
         *
         * @param position tab位置
         * @param view     Component
         * @param parent   ComponentContainer
         * @return Component
         */
        Component onIconView(int position, Component view, ComponentContainer parent);

        /**
         * 获取布局属性
         *
         * @return 布局属性
         */
        DependentLayout.LayoutConfig getLayoutConfig();
    }

    // @formatter:on
    private DirectionalLayout.LayoutConfig expandedTabLayoutParams;

    private final PageListener pageListener = new PageListener();

    /**
     * PageSlider页面切换监听
     */
    public PageSlider.PageChangedListener delegatePageListener;

    private DirectionalLayout tabsContainer;
    private PageSlider pager;

    private int tabCount;

    private int currentPosition = 0;

    private Paint rectPaint;
    private Paint dividerPaint;

    private boolean checkedTabWidths = false;

    private int indicatorColor = 0xFF666666;
    private int underlineColor = 0x1A000000;
    private int dividerColor = 0x1A000000;

    private boolean shouldExpand = true;
    private boolean textAllCaps = true;

    private int scrollOffset = 52;
    private int indicatorHeight = 0;
    private int underlineHeight = 2;
    private int dividerPadding = 12;
    private int tabPadding = 24;
    private int tabPaddingTopBottom = 0;
    private int dividerWidth = 1;

    private int tabTextSize = 15;
    private int tabTextColor = 0xFF666666;
    private int tabTextSelectColor = 0xFF666666;

    private Font tabTypefaceStyle = Font.DEFAULT;
    private int tabDrawMode = DRAW_MODE_NORMAL;

    /**
     * 绘制模式NORMAL
     */
    public static final int DRAW_MODE_NORMAL = 0;

    /**
     * 绘制模式TEXT
     */
    public static final int DRAW_MODE_TEXT = 1;

    private int lastScrollX = 0;

    private Locale locale;
    private OnTabClickListener mOnTabClickListener;

    /**
     * OnTabClickListener
     *
     * @since 2021-04-30
     */
    public interface OnTabClickListener {
        /**
         * 点击接口
         *
         * @param pos 位置
         */
        void onClick(int pos);
    }

    /**
     * 构造函数
     *
     * @param context 上下文
     * @param attrSet AttrSet
     */
    public AdvancedPagerSlidingTabStrip(Context context, AttrSet attrSet) {
        this(context, attrSet,"");
    }

    /**
     * 构造函数
     *
     * @param context   上下文
     * @param attrSet   AttrSet
     * @param styleName String
     */
    public AdvancedPagerSlidingTabStrip(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        setMatchViewportEnabled(true);

        tabsContainer = new DirectionalLayout(context);
        tabsContainer.setOrientation(DirectionalLayout.HORIZONTAL);
        LayoutConfig layoutConfig = new LayoutConfig(LayoutConfig.MATCH_PARENT, LayoutConfig.MATCH_PARENT);
        tabsContainer.setLayoutConfig(layoutConfig);
        addComponent(tabsContainer);

        indicatorColor = TypedAttrUtils.getIntColor(attrSet, "apTabIndicatorColor", indicatorColor);
        underlineColor = TypedAttrUtils.getIntColor(attrSet, "apTabUnderlineColor", underlineColor);
        dividerColor = TypedAttrUtils.getIntColor(attrSet, "apTabDividerColor", dividerColor);
        indicatorHeight = TypedAttrUtils.getDimensionPixelSize(attrSet, "apTabIndicatorHeight", indicatorHeight);
        underlineHeight = TypedAttrUtils.getDimensionPixelSize(attrSet, "apTabUnderlineHeight", underlineHeight);
        dividerPadding = TypedAttrUtils.getDimensionPixelSize(attrSet, "apTabDividerPadding", dividerPadding);
        tabPadding = TypedAttrUtils.getDimensionPixelSize(attrSet, "apTabPaddingLeftRight", tabPadding);
        tabPaddingTopBottom = TypedAttrUtils.getDimensionPixelSize(attrSet, "apTabPaddingTopBottom", tabPaddingTopBottom);
        shouldExpand = TypedAttrUtils.getBoolean(attrSet, "apTabShouldExpand", shouldExpand);
        scrollOffset = TypedAttrUtils.getDimensionPixelSize(attrSet, "apTabScrollOffset", scrollOffset);
        textAllCaps = TypedAttrUtils.getBoolean(attrSet, "apTabTextAllCaps", textAllCaps);
        tabTextSelectColor = TypedAttrUtils.getIntColor(attrSet, "apTabTextSelectColor", dividerColor);
        tabDrawMode = TypedAttrUtils.getInt(attrSet, "apTabDrawMode", DRAW_MODE_NORMAL);
        tabTextSize = TypedAttrUtils.getDimensionPixelSize(attrSet, "apTabTextSize", tabTextSize);
        tabTextColor = TypedAttrUtils.getIntColor(attrSet, "apTabTextColor", tabTextColor);

        rectPaint = new Paint();
        rectPaint.setAntiAlias(true);
        rectPaint.setStyle(Paint.Style.FILL_STYLE);

        dividerPaint = new Paint();
        dividerPaint.setAntiAlias(true);
        dividerPaint.setStrokeWidth(dividerWidth);

        expandedTabLayoutParams = new DirectionalLayout.LayoutConfig(0, LayoutConfig.MATCH_PARENT,
                TableLayout.Alignment.ALIGNMENT_FILL, 1.0f);

        if (locale == null) {
            locale = getResourceManager().getConfiguration().getFirstLocale();
        }

        if (mViewTabCache == null) {
            mViewTabCache = new PlainArray<>();
        }

        addDrawTask(this);
        setEstimateSizeListener(this);
    }

    /**
     * 设置PageSlider
     *
     * @param pager PageSlider
     */
    public void setViewPager(PageSlider pager) {
        this.pager = pager;

        if (pager.getProvider() == null) {
            throw new IllegalStateException("ViewPager does not have adapter instance.");
        }

        pager.addPageChangedListener(pageListener);

        notifyDataSetChanged();
    }

    public void setOnPageChangeListener(PageSlider.PageChangedListener listener) {
        this.delegatePageListener = listener;
    }

    /**
     * 更新数据
     */
    public void notifyDataSetChanged() {
        tabsContainer.removeAllComponents();
        tabCount = pager.getProvider().getCount();

        for (int i = 0; i < tabCount; i++) {
            if (pager.getProvider() instanceof IconTabProvider) {
                addIconTab(i, ((IconTabProvider) pager.getProvider()).getPageIcon(i), pager.getProvider().getPageTitle(i));
            } else if (pager.getProvider() instanceof ViewTabProvider) {
                addViewTab(i, ((ViewTabProvider) pager.getProvider()), pager.getProvider().getPageTitle(i));
            } else {
                addTextTab(i, pager.getProvider().getPageTitle(i));
            }
        }

        updateTabStyles();
        checkedTabWidths = false;
        pageListener.onPageChosen(0);
    }

    private void addTextTab(final int position, String title) {
        DependentLayout tab = new DependentLayout(getContext());
        tab.setClickedListener(v -> {
            if (mOnTabClickListener != null) {
                mOnTabClickListener.onClick(position);
            }
            scrollToChild(position, 0);
            pager.setCurrentPage(position);
        });

        Text txt = new Text(getContext());
        txt.setText(title);
        txt.setFocusable(Text.FOCUS_ENABLE);
        txt.setTextAlignment(TextAlignment.CENTER);
        txt.setMaxTextLines(1);
        txt.setId(ResourceTable.String_id_tab_txt);
        DependentLayout.LayoutConfig txtParams = new DependentLayout.LayoutConfig(LayoutConfig.MATCH_CONTENT, LayoutConfig.MATCH_CONTENT);
        txtParams.addRule(DependentLayout.LayoutConfig.CENTER_IN_PARENT);
        if (pager.getProvider() instanceof LayoutProvider) {
            LayoutProvider layoutProvider = (LayoutProvider) pager.getProvider();
            for (Integer rule : layoutProvider.getPageRule(position)) {
                txtParams.addRule(rule);
            }
            Margins margins = layoutProvider.getPageMargins(position);
            if (margins != null) {
                txtParams.setMargins(margins.mLeft, margins.mTop, margins.mRight, margins.mBottom);
            }
        }
        txt.setLayoutConfig(txtParams);

        int result = getResValue(ResourceTable.Float_psts_dot_wh);
        DependentLayout.LayoutConfig layoutParams = new DependentLayout.LayoutConfig(result, result);
        Text dot = new Text(getContext());
        dot.setTextColor(Color.WHITE);
        ShapeElement shapeElement = new ShapeElement();
        shapeElement.setRgbColor(new RgbColor(Color.BLUE.getValue()));
        dot.setBackground(shapeElement);
        dot.setTextAlignment(TextAlignment.CENTER);
        dot.setMaxTextLines(1);
        dot.setTextSize(getResValue(ResourceTable.Float_psts_dot_txt_size));

        Element dot_drawable = new ShapeElement(this.mContext, ResourceTable.Graphic_apsts_tips);

        boolean hasRule = false;
        layoutParams.setMargins(0, 0, getResValue(ResourceTable.Float_psts_dot_m_right), 0);
        if (pager.getProvider() instanceof TipsProvider) {
            TipsProvider tipsProvider = (TipsProvider) pager.getProvider();
            for (Integer rule : tipsProvider.getTipsRule(position)) {
                layoutParams.addRule(rule);
                hasRule = true;
            }
            Margins margins = tipsProvider.getTipsMargins(position);
            if (margins != null) {
                layoutParams.setMargins(margins.mLeft, margins.mTop, margins.mRight, margins.mBottom);
            }

            Element drawable = tipsProvider.getTipsDrawable(position);
            if (drawable != null) {
                dot_drawable = drawable;
            }
        }

        if (!hasRule) {
            layoutParams.addRule(DependentLayout.LayoutConfig.ALIGN_RIGHT, ResourceTable.String_id_tab_txt);
            layoutParams.addRule(DependentLayout.LayoutConfig.ALIGN_TOP, ResourceTable.String_id_tab_txt);
            int halfSize = getResValue(ResourceTable.Float_psts_dot_m_tv_right);
            layoutParams.setMargins(0, 0, -halfSize, 0);
        }

        dot.setBackground(dot_drawable);
        dot.setLayoutConfig(layoutParams);

        tab.addComponent(txt, 0);
        tab.addComponent(dot, 1);
        dot.setVisibility(Component.INVISIBLE);
        tabsContainer.addComponent(tab);
    }

    /**
     * 展示红点
     *
     * @param index 当前位置
     */
    public void showDot(int index) {
        DependentLayout tab = (DependentLayout) tabsContainer.getComponentAt(index);
        Text dot_layout = (Text) tab.getComponentAt(tab.getChildCount() - 1);
        dot_layout.setText("");
        dot_layout.setVisibility(Component.VISIBLE);
    }

    /**
     * 展示红点
     *
     * @param index  当前位置
     * @param dotTxt 红点文字
     */
    public void showDot(int index, String dotTxt) {
        DependentLayout tab = (DependentLayout) tabsContainer.getComponentAt(index);
        Text dot_layout = (Text) tab.getComponentAt(tab.getChildCount() - 1);
        dot_layout.setText(dotTxt);
        dot_layout.setPaddingLeft(10);
        dot_layout.setPaddingRight(10);
        dot_layout.setVisibility(Component.VISIBLE);
    }

    /**
     * 隐藏红点
     *
     * @param index 当前位置
     */
    public void hideDot(int index) {
        DependentLayout tab = (DependentLayout) tabsContainer.getComponentAt(index);
        Text dot_layout = (Text) tab.getComponentAt(tab.getChildCount() - 1);
        dot_layout.setVisibility(Component.INVISIBLE);
    }

    private PlainArray<Component> mViewTabCache;

    private Component getTabView(int position) {
        return mViewTabCache.get(position).get();
    }

    private void setTabView(int position, Component view) {
        mViewTabCache.put(position, view);
    }

    private void addViewTab(final int position, ViewTabProvider provider, String title) {
        DependentLayout tab = new DependentLayout(getContext());
        tab.setClickedListener(v -> {
            if (mOnTabClickListener != null) {
                mOnTabClickListener.onClick(position);
            }
            scrollToChild(position, 0);
            pager.setCurrentPage(position);
        });

        // 文本和图
        Text txt = new Text(getContext());
        txt.setText(title);
        txt.setFocusable(Text.FOCUS_ENABLE);
        txt.setTextAlignment(TextAlignment.CENTER);
        txt.setMaxTextLines(1);
        txt.setId(ResourceTable.String_id_tab_txt);
        DependentLayout.LayoutConfig txtParams = new DependentLayout.LayoutConfig(
                DependentLayout.LayoutConfig.MATCH_CONTENT,
                DependentLayout.LayoutConfig.MATCH_CONTENT);
        txtParams.addRule(DependentLayout.LayoutConfig.HORIZONTAL_CENTER);
        txtParams.addRule(DependentLayout.LayoutConfig.ALIGN_PARENT_BOTTOM);
        if (pager.getProvider() instanceof LayoutProvider) {
            LayoutProvider layoutProvider = (LayoutProvider) pager.getProvider();
            for (Integer rule : layoutProvider.getPageRule(position)) {
                txtParams.addRule(rule);
            }
            Margins margins = layoutProvider.getPageMargins(position);
            if (margins != null) {
                txtParams.setMargins(margins.mLeft, margins.mTop, margins.mRight, margins.mBottom);
            }
        }
        txtParams.addRule(DependentLayout.LayoutConfig.HORIZONTAL_CENTER);
        txtParams.addRule(DependentLayout.LayoutConfig.ALIGN_PARENT_BOTTOM);
        txt.setLayoutConfig(txtParams);

        // 使用缓存
        Component view = provider.onIconView(position, null, tab);

        // 保存view到缓存中
        setTabView(position, view);

        DependentLayout.LayoutConfig viewLayoutParams
                = provider.getLayoutConfig();
        viewLayoutParams.addRule(DependentLayout.LayoutConfig.HORIZONTAL_CENTER);
        viewLayoutParams.addRule(DependentLayout.LayoutConfig.ABOVE, ResourceTable.String_id_tab_txt);
        view.setLayoutConfig(viewLayoutParams);

        DependentLayout.LayoutConfig layoutParams =
                new DependentLayout.LayoutConfig(ComponentContainer.LayoutConfig.MATCH_CONTENT,
                        ComponentContainer.LayoutConfig.MATCH_CONTENT);
        Text dot = new Text(getContext());
        dot.setTextColor(Color.WHITE);

        ShapeElement shapeElement = new ShapeElement();
        shapeElement.setRgbColor(new RgbColor(Color.BLUE.getValue()));
        dot.setBackground(shapeElement);
        dot.setTextAlignment(TextAlignment.CENTER);
        dot.setMaxTextLines(1);
        dot.setTextSize(getResValue(ResourceTable.Float_psts_dot_txt_size));

        Element dot_drawable = new ShapeElement(this.mContext, ResourceTable.Graphic_apsts_tips);

        boolean hasRule = false;
        layoutParams.setMargins(0, 15, getResValue(ResourceTable.Float_psts_dot_m_right), 0);
        if (pager.getProvider() instanceof TipsProvider) {
            TipsProvider tipsProvider = (TipsProvider) pager.getProvider();
            for (Integer rule : tipsProvider.getTipsRule(position)) {
                layoutParams.addRule(rule);
                hasRule = true;
            }
            Margins margins = tipsProvider.getTipsMargins(position);
            if (margins != null) {
                layoutParams.setMargins(margins.mLeft, margins.mTop, margins.mRight, margins.mBottom);
            }
            Element drawable = tipsProvider.getTipsDrawable(position);
            if (drawable != null) {
                dot_drawable = drawable;
            }
        }

        if (!hasRule) {
            layoutParams.addRule(DependentLayout.LayoutConfig.ALIGN_PARENT_RIGHT);
        }

        dot.setBackground(dot_drawable);
        dot.setLayoutConfig(layoutParams);

        tab.addComponent(txt, 0);
        tab.addComponent(view, 1);
        tab.addComponent(dot, 2);
        dot.setVisibility(Component.INVISIBLE);
        tabsContainer.addComponent(tab);
    }

    private void addIconTab(final int position, Object res, String text) {
        DependentLayout tab = new DependentLayout(getContext());
        tab.setClickedListener(v -> {
            if (mOnTabClickListener != null) {
                mOnTabClickListener.onClick(position);
            }
            scrollToChild(position, 0);
            pager.setCurrentPage(position);
        });

        // 文本和图
        Text txt = new Text(getContext());
        txt.setText(text);
        txt.setFocusable(Text.FOCUS_ENABLE);
        txt.setTextAlignment(TextAlignment.CENTER);
        txt.setMaxTextLines(1);
        txt.setId(ResourceTable.String_id_tab_txt);
        DependentLayout.LayoutConfig txtParams = new DependentLayout.LayoutConfig(
                DependentLayout.LayoutConfig.MATCH_CONTENT,
                DependentLayout.LayoutConfig.MATCH_CONTENT);
        txtParams.addRule(DependentLayout.LayoutConfig.CENTER_IN_PARENT);
        if (pager.getProvider() instanceof LayoutProvider) {
            LayoutProvider layoutProvider = (LayoutProvider) pager.getProvider();
            for (Integer rule : layoutProvider.getPageRule(position)) {
                txtParams.addRule(rule);
            }
            Margins margins = layoutProvider.getPageMargins(position);
            if (margins != null) {
                txtParams.setMargins(margins.mLeft, margins.mTop, margins.mRight, margins.mBottom);
            }
        }
        txt.setLayoutConfig(txtParams);

        setViewResource(position, res, txt);

        DependentLayout.LayoutConfig layoutParams = new DependentLayout.LayoutConfig(ComponentContainer.LayoutConfig.MATCH_CONTENT, ComponentContainer.LayoutConfig.MATCH_CONTENT);
        Text dot = new Text(getContext());
        dot.setTextColor(Color.WHITE);
        ShapeElement shapeElement = new ShapeElement();
        shapeElement.setRgbColor(new RgbColor(Color.BLUE.getValue()));
        dot.setBackground(shapeElement);
        dot.setTextAlignment(TextAlignment.CENTER);
        dot.setMaxTextLines(1);
        dot.setTextSize(getResValue(ResourceTable.Float_psts_dot_txt_size));

        Element dot_drawable = new ShapeElement(this.mContext, ResourceTable.Graphic_apsts_tips);

        boolean hasRule = false;
        layoutParams.setMargins(0, 15, getResValue(ResourceTable.Float_psts_dot_m_right), 0);
        if (pager.getProvider() instanceof TipsProvider) {
            TipsProvider tipsProvider = (TipsProvider) pager.getProvider();
            for (Integer rule : tipsProvider.getTipsRule(position)) {
                layoutParams.addRule(rule);
                hasRule = true;
            }
            Margins margins = tipsProvider.getTipsMargins(position);
            if (margins != null) {
                layoutParams.setMargins(margins.mLeft, margins.mTop, margins.mRight, margins.mBottom);
            }
            Element drawable = tipsProvider.getTipsDrawable(position);
            if (drawable != null) {
                dot_drawable = drawable;
            }
        }

        if (!hasRule) {
            layoutParams.addRule(DependentLayout.LayoutConfig.ALIGN_PARENT_RIGHT);
        }

        dot.setBackground(dot_drawable);
        dot.setLayoutConfig(layoutParams);

        tab.addComponent(txt, 0);
        tab.addComponent(dot, 1);
        dot.setVisibility(Component.INVISIBLE);
        tabsContainer.addComponent(tab);
    }

    /**
     * 获取tab Component
     *
     * @param pos tab位置
     * @return Component tab元素
     */
    public Component getTabAt(int pos) {
        if (pos >= tabsContainer.getChildCount()) {
            throw new IllegalStateException("pos is too big.");
        }
        return tabsContainer.getComponentAt(pos);
    }

    private void updateTabStyles() {
        for (int i = 0; i < tabCount; i++) {
            Component v = tabsContainer.getComponentAt(i);
            v.setLayoutConfig(expandedTabLayoutParams);

            if (shouldExpand) {
                v.setPadding(0, 0, 0, 0);
            } else {
                v.setPadding(tabPadding, tabPaddingTopBottom, tabPadding, tabPaddingTopBottom);
            }

            if (v instanceof DependentLayout) {
                DependentLayout tab = (DependentLayout) v;
                Text tv = (Text) tab.getComponentAt(0);
                tv.setTextSize(tabTextSize, Text.TextSizeType.FP);
                tv.setFont(tabTypefaceStyle);
                tv.setTextColor(new Color(tabTextColor));

                // setAllCaps() is only available from API 14, so the upper case is made manually if we are on a
                // pre-ICS-build
                if (textAllCaps) {
                    tv.setText(tv.getText().toUpperCase(locale));
                }
            }
        }
    }

    /**
     * 设置布局属性
     *
     * @return 是否设置成功
     */
    public boolean setTabLayoutParams() {
        if (pager.getProvider() instanceof LayoutProvider) {
            LayoutProvider weightProvider = (LayoutProvider) pager.getProvider();
            if (weightProvider == null) {
                return false;
            }
            for (int i = 0; i < tabCount; i++) {
                float weight = weightProvider.getPageWeight(i);
                if (weight != 0.0f) {
                    DirectionalLayout.LayoutConfig layoutParams = new DirectionalLayout.LayoutConfig(0, DirectionalLayout.LayoutConfig.MATCH_PARENT, TableLayout.Alignment.ALIGNMENT_FILL, weight == 0.0f ? 1.0f : weight);
                    tabsContainer.getComponentAt(i).setLayoutConfig(layoutParams);
                } else {
                    tabsContainer.getComponentAt(i).setLayoutConfig(expandedTabLayoutParams);
                }
            }
        }
        return false;
    }

    @Override
    public boolean onEstimateSize(int widthMeasureSpec, int heightMeasureSpec) {
        if (!shouldExpand || EstimateSpec.getMode(widthMeasureSpec) == EstimateSpec.UNCONSTRAINT) {
            setTabLayoutParams();
            return false;
        }

        int myWidth = getEstimatedWidth();
        int childWidth = 0;
        for (int i = 0; i < tabCount; i++) {
            childWidth += tabsContainer.getComponentAt(i).getEstimatedWidth();
        }

        if (!checkedTabWidths && childWidth > 0 && myWidth > 0) {
            if (childWidth <= myWidth) {
                if (!setTabLayoutParams()) {
                    for (int i = 0; i < tabCount; i++) {
                        tabsContainer.getComponentAt(i).setLayoutConfig(expandedTabLayoutParams);
                    }
                }
            }

            checkedTabWidths = true;
        }
        return true;
    }

    private void scrollToChild(int position, int offset) {
        if (tabCount == 0) {
            return;
        }

        int newScrollX = tabsContainer.getComponentAt(position).getLeft() + offset;

        if (position > 0 || offset > 0) {
            newScrollX -= scrollOffset;
        }

        if (newScrollX != lastScrollX) {
            lastScrollX = newScrollX;
            scrollTo(newScrollX, 0);
        }
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        if (tabCount == 0) {
            return;
        }

        if (tabDrawMode == DRAW_MODE_NORMAL) {
            drawTabNormalMode(canvas);
        } else {
            drawTabTextMode(canvas);
        }
    }

    private void drawTabNormalMode(Canvas canvas) {
        final int height = getHeight();
        // 设置提示下划线的颜色
        rectPaint.setColor(new Color(indicatorColor));

        Component currentTab = tabsContainer.getComponentAt(currentPosition);
        float lineLeft = currentTab.getLeft();
        float lineRight = currentTab.getRight();

        // 绘制提示下划线
        canvas.drawRect(lineLeft, height - indicatorHeight, lineRight, height, rectPaint);

        // 绘制下划线
        rectPaint.setColor(new Color(underlineColor));
        canvas.drawRect(0, height - underlineHeight, tabsContainer.getWidth(), height, rectPaint);

        // 绘制分割线
        dividerPaint.setColor(new Color(dividerColor));
        for (int i = 0; i < tabCount - 1; i++) {
            Component tab = tabsContainer.getComponentAt(i);
            canvas.drawLine(tab.getRight(), dividerPadding, tab.getRight(), height - dividerPadding, dividerPaint);
        }
    }

    private void drawTabTextMode(Canvas canvas) {
        final int height = getHeight();

        // 设置提示下划线的颜色
        rectPaint.setColor(new Color(indicatorColor));

        Component currentTab = tabsContainer.getComponentAt(currentPosition);
        float lineLeft = currentTab.getLeft();

        Component currentTextView = ((DependentLayout) currentTab).getComponentAt(0);
        float currentTextViewLeft = currentTextView.getLeft();
        float currentTextViewRight = currentTextView.getRight();

        // 绘制提示下划线
        float r = ((float) indicatorHeight) / 2;
        canvas.drawCircle((float) ((double) lineLeft + (double) currentTextViewLeft + (double) r), (float) (height - indicatorHeight + (double) r), r, rectPaint);
        canvas.drawCircle((float) ((double) lineLeft + (double) currentTextViewRight - (double) r), (float) (height - indicatorHeight + (double) r), r, rectPaint);

        canvas.drawRect((float) ((double) lineLeft + (double) currentTextViewLeft + (double) r), height - indicatorHeight, (float) ((double) lineLeft + (double) currentTextViewRight - (double) r), height, rectPaint);

        // 分割线paint
        dividerPaint.setColor(new Color(dividerColor));

        // 下划线paint
        rectPaint.setColor(new Color(underlineColor));

        for (int i = 0; i < tabCount; i++) {
            Component tab = tabsContainer.getComponentAt(i);
            //绘制分割线
            if (i < tabCount - 1) {
                canvas.drawLine(tab.getRight(), dividerPadding, tab.getRight(), height - dividerPadding, dividerPaint);
            }
            Component tabTextView = ((DependentLayout) tab).getComponentAt(0);
            canvas.drawRect(tab.getLeft() + tabTextView.getLeft(), height - underlineHeight, tab.getLeft() + tabTextView.getRight(), height, rectPaint);
        }
    }

    /**
     * PageListener
     *
     * @since 2021-04-30
     */
    private class PageListener implements PageSlider.PageChangedListener {
        @Override
        public void onPageSliding(int position, float positionOffset, int positionOffsetPixels) {
            if (tabsContainer != null && tabsContainer.getComponentAt(position) != null) {
                scrollToChild(position, (int) (positionOffset * tabsContainer.getComponentAt(position).getWidth()));
            }

            invalidate();

            if (delegatePageListener != null) {
                delegatePageListener.onPageSliding(position, positionOffset, positionOffsetPixels);
            }
        }

        @Override
        public void onPageSlideStateChanged(int state) {
            if (state == PageSlider.SCROLL_IDLE_STAGE) {
                scrollToChild(pager.getCurrentPage(), 0);
            }

            if (delegatePageListener != null) {
                delegatePageListener.onPageSlideStateChanged(state);
            }
        }

        @Override
        public void onPageChosen(int position) {
            setSelectItem(position);

            if (delegatePageListener != null) {
                delegatePageListener.onPageChosen(position);
            }
            currentPosition = position;
            invalidate();
        }
    }

    private void setViewResource(int position, Object obj, Text view) {
        IconTabProvider iconTabProvider = (IconTabProvider) pager.getProvider();
        Rect rect = iconTabProvider.getPageIconBounds(position);
        Element drawable = null;
        if (obj instanceof Integer) {
            int resId = (int) obj;
            if (resId != 0) {
                drawable = getResElement(resId);
            }
        } else if (obj instanceof PixelMap) {
            PixelMap bitmap = (PixelMap) obj;
            drawable = new PixelMapElement(bitmap);

        } else if (obj instanceof Element) {
            drawable = (Element) obj;
        }

        if (drawable != null) {
            if (rect != null) {
                drawable.setBounds(rect);
                view.setAroundElements(null, drawable, null, null);
            } else {
                view.setAroundElements(null, drawable, null, null);
            }
        }
    }

    /**
     * 选中item刷新状态
     *
     * @param position item位置
     */
    public void setSelectItem(int position) {
        for (int i = 0; i < tabsContainer.getChildCount(); i++) {
            DependentLayout linearLayout = (DependentLayout) tabsContainer.getComponentAt(i);
            if (i == position) {
                ((Text) linearLayout.getComponentAt(0)).setTextColor(new Color(tabTextSelectColor));
                if (pager.getProvider() instanceof IconTabProvider) {
                    Object obj = ((IconTabProvider) pager.getProvider()).getPageSelectIcon(i);
                    setViewResource(position, obj, (Text) linearLayout.getComponentAt(0));
                } else if (pager.getProvider() instanceof ViewTabProvider) {
                    Component view = ((ViewTabProvider) pager.getProvider()).onSelectIconView(i, getTabView(i), linearLayout);
                    setTabView(i, view);
                    changeIconView(linearLayout, view);
                }
            } else {
                ((Text) linearLayout.getComponentAt(0)).setTextColor(new Color(tabTextColor));
                if (pager.getProvider() instanceof IconTabProvider) {
                    Object obj = ((IconTabProvider) pager.getProvider()).getPageIcon(i);
                    setViewResource(position, obj, (Text) linearLayout.getComponentAt(0));
                } else if (pager.getProvider() instanceof ViewTabProvider) {
                    Component view = ((ViewTabProvider) pager.getProvider()).onIconView(i, getTabView(i), linearLayout);
                    setTabView(i, view);
                    changeIconView(linearLayout, view);
                }
            }
        }
    }

    private void changeIconView(DependentLayout linearLayout, Component view) {
        DependentLayout.LayoutConfig viewLayoutParams
                = ((ViewTabProvider) pager.getProvider()).getLayoutConfig();
        viewLayoutParams.addRule(DependentLayout.LayoutConfig.HORIZONTAL_CENTER);
        viewLayoutParams.addRule(DependentLayout.LayoutConfig.ABOVE, ResourceTable.String_id_tab_txt);
        view.setLayoutConfig(viewLayoutParams);
        linearLayout.removeComponentAt(1);
        linearLayout.addComponent(view, 1);
    }

    /**
     * 设置指标颜色
     *
     * @param indicatorColor 颜色值
     */
    public void setIndicatorColor(int indicatorColor) {
        this.indicatorColor = indicatorColor;
        invalidate();
    }

    /**
     * 设置指标颜色资源
     *
     * @param resId 资源id
     */
    public void setIndicatorColorResource(int resId) {
        this.indicatorColor = getColorValue(resId);
        invalidate();
    }

    public int getIndicatorColor() {
        return this.indicatorColor;
    }

    /**
     * 设置指标高度
     *
     * @param indicatorLineHeightPx 指标高度
     */
    public void setIndicatorHeight(int indicatorLineHeightPx) {
        this.indicatorHeight = indicatorLineHeightPx;
        invalidate();
    }

    public int getIndicatorHeight() {
        return indicatorHeight;
    }

    /**
     * 设置下划线颜色
     *
     * @param underlineColor 下划线颜色
     */
    public void setUnderlineColor(int underlineColor) {
        this.underlineColor = underlineColor;
        invalidate();
    }

    /**
     * 设置下划线颜色资源
     *
     * @param resId 资源id
     */
    public void setUnderlineColorResource(int resId) {
        this.underlineColor = getColorValue(resId);
        invalidate();
    }

    public int getUnderlineColor() {
        return underlineColor;
    }

    /**
     * 设置风格线颜色
     *
     * @param dividerColor 分割线颜色
     */
    public void setDividerColor(int dividerColor) {
        this.dividerColor = dividerColor;
        invalidate();
    }

    /**
     * 设置风格线颜色资源
     *
     * @param resId 分割线颜色资源id
     */
    public void setDividerColorResource(int resId) {
        this.dividerColor = getColorValue(resId);
        invalidate();
    }

    public int getDividerColor() {
        return dividerColor;
    }

    /**
     * 设置下划线高度
     *
     * @param underlineHeightPx 下划线高度值
     */
    public void setUnderlineHeight(int underlineHeightPx) {
        this.underlineHeight = underlineHeightPx;
        invalidate();
    }

    public int getUnderlineHeight() {
        return underlineHeight;
    }

    /**
     * 设置分割线间距
     *
     * @param dividerPaddingPx 分割线间距值
     */
    public void setDividerPadding(int dividerPaddingPx) {
        this.dividerPadding = dividerPaddingPx;
        invalidate();
    }

    public int getDividerPadding() {
        return dividerPadding;
    }

    /**
     * 设置滚动偏移量
     *
     * @param scrollOffsetPx 滚动偏移量
     */
    public void setScrollOffset(int scrollOffsetPx) {
        this.scrollOffset = scrollOffsetPx;
        invalidate();
    }

    public int getScrollOffset() {
        return scrollOffset;
    }

    /**
     * 设置是否平铺展开
     *
     * @param shouldExpand 是否展开
     */
    public void setShouldExpand(boolean shouldExpand) {
        this.shouldExpand = shouldExpand;
        postLayout();
    }

    public boolean getShouldExpand() {
        return shouldExpand;
    }

    public boolean isTextAllCaps() {
        return textAllCaps;
    }

    public void setAllCaps(boolean textAllCaps) {
        this.textAllCaps = textAllCaps;
    }

    /**
     * 设置字体大小
     *
     * @param textSizePx 字体大小
     */
    public void setTextSize(int textSizePx) {
        this.tabTextSize = textSizePx;
        updateTabStyles();
    }

    public int getTextSize() {
        return tabTextSize;
    }

    /**
     * 设置文字颜色
     *
     * @param textColor 文字颜色
     */
    public void setTextColor(int textColor) {
        this.tabTextColor = textColor;
        updateTabStyles();
    }

    /**
     * 设置字体颜色资源
     *
     * @param resId 资源id
     */
    public void setTextColorResource(int resId) {
        this.tabTextColor = getColorValue(resId);
        updateTabStyles();
    }

    public int getTextColor() {
        return tabTextColor;
    }

    /**
     * 设置字体类型
     *
     * @param style 字体类型
     */
    public void setTypeface(Font style) {
        this.tabTypefaceStyle = style;
        updateTabStyles();
    }

    /**
     * 设置tab左右padding
     *
     * @param paddingPx padding值
     */
    public void setTabPaddingLeftRight(int paddingPx) {
        this.tabPadding = paddingPx;
        updateTabStyles();
    }

    public int getTabPaddingLeftRight() {
        return tabPadding;
    }

    private int getResValue(int resId) {
        ResourceManager resManager = this.getResourceManager();
        int result = 0;
        try {
            result = (int) resManager.getElement(resId).getFloat();
        } catch (IOException | NotExistException | WrongTypeException e) {
            e.fillInStackTrace();
        }
        return result;
    }

    private int getColorValue(int resId) {
        ResourceManager resManager = this.getResourceManager();
        int color = 0;
        try {
            color = resManager.getElement(resId).getColor();
        } catch (IOException | NotExistException | WrongTypeException e) {
            e.fillInStackTrace();
        }
        return color;
    }

    private Element getResElement(int resId) {
        Element element = null;
        try {
            element = new PixelMapElement(this.getResourceManager().getResource(resId));
        } catch (IOException | NotExistException e) {
            e.fillInStackTrace();
        }
        return element;
    }
}
